package com.ruoyi.teaching.service.impl;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;

import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.core.exception.ServiceException;
import com.ruoyi.common.core.utils.DateUtils;
import com.ruoyi.common.security.utils.SecurityUtils;
import com.vladsch.flexmark.ast.Heading;
import com.vladsch.flexmark.html.HtmlRenderer;
import com.vladsch.flexmark.parser.Parser;
import com.vladsch.flexmark.util.ast.Node;
import com.vladsch.flexmark.util.options.MutableDataSet;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ruoyi.teaching.mapper.YaKnowledgePointsMapper;
import com.ruoyi.teaching.domain.YaKnowledgePoints;
import com.ruoyi.teaching.service.IYaKnowledgePointsService;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

/**
 * 知识点Service业务层处理
 *
 * @author ruoyi
 * @date 2025-03-19
 */
@Service
@Slf4j
public class YaKnowledgePointsServiceImpl extends ServiceImpl<YaKnowledgePointsMapper,YaKnowledgePoints> implements IYaKnowledgePointsService
{
    @Autowired
    private YaKnowledgePointsMapper yaKnowledgePointsMapper;

    /**
     * 查询知识点
     *
     * @param id 知识点主键
     * @return 知识点
     */
    @Override
    public YaKnowledgePoints selectYaKnowledgePointsById(Long id)
    {
        return yaKnowledgePointsMapper.selectYaKnowledgePointsById(id);
    }

    /**
     * 查询知识点列表
     *
     * @param yaKnowledgePoints 知识点
     * @return 知识点
     */
    @Override
    public List<YaKnowledgePoints> selectYaKnowledgePointsList(YaKnowledgePoints yaKnowledgePoints)
    {
        return yaKnowledgePointsMapper.selectYaKnowledgePointsList(yaKnowledgePoints);
    }

    /**
     * 新增知识点
     *
     * @param yaKnowledgePoints 知识点
     * @return 结果
     */
    @Override
    public int insertYaKnowledgePoints(YaKnowledgePoints yaKnowledgePoints)
    {
        yaKnowledgePoints.setCreateTime(DateUtils.getNowDate());
        return yaKnowledgePointsMapper.insertYaKnowledgePoints(yaKnowledgePoints);
    }

    /**
     * 修改知识点
     *
     * @param yaKnowledgePoints 知识点
     * @return 结果
     */
    @Override
    public int updateYaKnowledgePoints(YaKnowledgePoints yaKnowledgePoints)
    {
        yaKnowledgePoints.setUpdateTime(DateUtils.getNowDate());
        return yaKnowledgePointsMapper.updateYaKnowledgePoints(yaKnowledgePoints);
    }

    /**
     * 批量删除知识点
     *
     * @param ids 需要删除的知识点主键
     * @return 结果
     */
    @Override
    public int deleteYaKnowledgePointsByIds(Long[] ids)
    {
        return yaKnowledgePointsMapper.deleteYaKnowledgePointsByIds(ids);
    }

    /**
     * 删除知识点信息
     *
     * @param id 知识点主键
     * @return 结果
     */
    @Override
    public int deleteYaKnowledgePointsById(Long id)
    {
        return yaKnowledgePointsMapper.deleteYaKnowledgePointsById(id);
    }



    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map<String, Object> parseAndSave(MultipartFile file) {
        Map<String, Object> result;
        try {
            long begin = System.currentTimeMillis();
            log.debug("1.开始解析md:{}", file.getOriginalFilename());
            Node document = getDocument(file);
            long end = System.currentTimeMillis();
            log.debug("解析结束，耗时:{}------------------------------", end - begin);

            begin = System.currentTimeMillis();
            log.debug("2.开始提取知识点信息到YaKnowledgePoints对象");
            // 提取知识点信息
            List<YaKnowledgePoints> knowledgePointsList = extractKnowledgePoints(document);
            end = System.currentTimeMillis();
            log.debug("提取知识点结束，耗时:{}------------------------------", end - begin);

            begin = System.currentTimeMillis();
            log.debug("3.批量保存到数据库");
            result = checkAndSave(knowledgePointsList);
            end = System.currentTimeMillis();
            log.debug("批量保存到数据库结束，耗时:{}------------------------------", end - begin);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return result;
    }

    /**
     * 从MultipartFile读取文件内容
     * @param file 文件
     * @return 可解析的Node对象
     */
    private Node getDocument(MultipartFile file) throws IOException {
        String markdownContent = readMarkdownFile(file);
        // 配置Flexmark解析器
        MutableDataSet options = new MutableDataSet();
        Parser parser = Parser.builder(options).build();
        // 解析Markdown内容
        return parser.parse(markdownContent);
    }

    /**
     * 校验并保存知识点
     * @param knowledgePointsList 知识点列表
     * @return 结果(更新列表,新增列表)
     */
    private Map<String, Object> checkAndSave(List<YaKnowledgePoints> knowledgePointsList) {
        Map<String, Object> result = new HashMap<>();
        if (CollectionUtils.isEmpty(knowledgePointsList)) {
            return result;
        }
        ArrayList<YaKnowledgePoints> newList = new ArrayList<>();
        ArrayList<String> updateNameList = new ArrayList<>();
        ArrayList<String> newNameList = new ArrayList<>();
        knowledgePointsList.forEach(knowledgePoint -> {
            LambdaUpdateWrapper<YaKnowledgePoints> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.eq(YaKnowledgePoints::getName,knowledgePoint.getName());
            int update = yaKnowledgePointsMapper.update(knowledgePoint, updateWrapper);
            if (update == 0) {
                newNameList.add(knowledgePoint.getName());
                newList.add(knowledgePoint);
            } else {
                updateNameList.add(knowledgePoint.getName());
            }
        });
        this.saveBatch(newList,100);
        result.put("newList", newNameList);
        result.put("updateList", updateNameList);
        return result;
    }

    /**
     * 去除html标签
     * @param html
     * @return
     */
    private static String removeHtmlTags(String html) {
        if (html == null) {
            return null;
        }
        return html.replaceAll("<[^>]*>", "");
    }

    /**
     * 提取知识点信息
     * @param document
     * @return
     */
    private static List<YaKnowledgePoints> extractKnowledgePoints(Node document) {
        List<YaKnowledgePoints> knowledgePointsList = new ArrayList<>();
        YaKnowledgePoints currentPoint = null;
        StringBuilder currentText = new StringBuilder();

        // 配置Flexmark解析器
        MutableDataSet options = new MutableDataSet();
        HtmlRenderer renderer = HtmlRenderer.builder(options).build();
        String contentType = "";

        String username = SecurityUtils.getUsername();
        Date nowDate = DateUtils.getNowDate();
        // 遍历AST节点
        for (Node node = document.getFirstChild(); node != null; node = node.getNext()) {

            if (node instanceof Heading) {

                Heading heading = (Heading) node;
                int level = heading.getLevel();
                String text = renderer.render(node).trim();
                if (StringUtils.isEmpty(text)) {
                    log.warn("标题为空,直接忽略");
                    continue;
                }

                if (level == 2) { // ## 标题
                    //把最后的提取到的文本添加到知识点对象中
                    extracted(contentType, currentPoint, currentText);
                    currentText.setLength(0);
                    currentPoint = new YaKnowledgePoints();
                    currentPoint.setName(removeHtmlTags(text));
                    currentPoint.setCreateBy(username);
                    currentPoint.setCreateTime(nowDate);
                    knowledgePointsList.add(currentPoint);
                } else if (level == 3) { // ### 标题
                    if (currentPoint == null) {
                        throw new ServiceException("格式不正确，没有二级标题");
                    }
                    //如果是3级标题，就将之前读到的文本添加到知识点对象中
                    extracted(contentType, currentPoint, currentText);

                    String subHeading = text.toLowerCase();
                    if (subHeading.contains("why")) {
                        contentType = "why";
                    } else if (subHeading.contains("what")) {
                        contentType = "what";
                    } else if (subHeading.contains("how")) {
                        contentType = "how";
                    } else if (subHeading.contains("when")) {
                        contentType = "when";
                    } else if (subHeading.contains("总结")) {
                        contentType = "总结";
                    } else if (subHeading.contains("高频面试题")) {
                        contentType = "高频面试题";
                    }
                    currentText.setLength(0);
                }else{ // #### 标题以及其他
                    currentText.append(renderer.render(node));
                }
            } else {
                currentText.append(renderer.render(node));
            }
        }
        //将最后的文本提取到对应的知识点对象中
        if (StringUtils.isNotEmpty(currentText)) {
            extracted(contentType, currentPoint, currentText);
        }
        //不要list中知识点what为空的过滤掉
        knowledgePointsList.removeIf(point -> point.getWhat() == null);
        return knowledgePointsList;
    }

    /**
     * 根据标题类型，将文本添加到对应的知识点对象中
     * @param contentType 标题类型
     * @param currentPoint 知识点对象
     * @param currentText 文本内容
     */
    private static void extracted(String contentType, YaKnowledgePoints currentPoint, StringBuilder currentText) {
        if (StringUtils.isNotEmpty(contentType)) {
            String string = currentText.toString();
            switch (contentType) {
                case "why":
                    currentPoint.setWhy(string);
                    break;
                case "what":
                    currentPoint.setWhat(string);
                    break;
                case "how":
                    currentPoint.setHow(string);
                    break;
                case "when":
                    currentPoint.setWhenUse(string);
                    break;
                case "总结":
                    currentPoint.setSummary(string);
                    break;
                case "高频面试题":
                    currentPoint.setInterview(string);
                    break;
                default:
                    throw new ServiceException("未知的标题类型：" + contentType);
            }
            currentText.setLength(0);
        }
    }

    /**
     * 从读取MultipartFile中读取到文本
     * @param file 上传的文件
     * @return 文本内容
     */
    public String readMarkdownFile(MultipartFile file) throws IOException {
        // 检查文件是否为空
        if (file.isEmpty()) {
            throw new IllegalArgumentException("File is empty");
        }

        // 检查文件扩展名是否为.md
        if (!file.getOriginalFilename().toLowerCase().endsWith(".md")) {
            throw new IllegalArgumentException("File must be a Markdown file (.md)");
        }

        // 使用BufferedReader读取文件内容
        StringBuilder contentBuilder = new StringBuilder();
        try (BufferedReader reader = new BufferedReader(new InputStreamReader(file.getInputStream()))) {
            String line;
            while ((line = reader.readLine()) != null) {
                contentBuilder.append(line).append(System.lineSeparator());
            }
        }

        return contentBuilder.toString();
    }


}
